package eu.fishcode.android.ui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.logging.Level;

import javax.imageio.ImageIO;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingConstants;
import javax.swing.SwingWorker;
import javax.swing.Timer;

import eu.fishcode.android.ui.component.Header;
import eu.fishcode.android.ui.component.StatusBar;
import eu.fishcode.android.ui.component.ToolBar;
import eu.fishcode.android.utils.AnimatedGifEncoder;
import eu.fishcode.android.utils.BootAnimationZip;
import eu.fishcode.android.utils.CommonAdb;
import eu.fishcode.android.utils.Utils;

public class MainWindow extends JFrame implements ActionListener {

	class MakeGifTask extends SwingWorker<String, String> {

		private final String filePath;

		public MakeGifTask(String file) {
			this.filePath = file;
		}

		@Override
		public String doInBackground() {
			// TODO da sistemare e commentare
			Utils.logger.log(Level.INFO, this.filePath);
			final AnimatedGifEncoder gif = new AnimatedGifEncoder();
			gif.start(this.filePath);
			gif.setDelay(MainWindow.this.timer.getDelay());
			for (MainWindow.this.currentFrame = 0; MainWindow.this.currentFrame < MainWindow.this.partFile.length; MainWindow.this.currentFrame++) {
				BufferedImage bufferedImageIO;
				try {
					bufferedImageIO = ImageIO
							.read(MainWindow.this.partFile[MainWindow.this.currentFrame]);
					gif.addFrame(bufferedImageIO);
					MainWindow.this.statusBar.setMessage("Export ("
							+ MainWindow.this.currentFrame + " / "
							+ MainWindow.this.partFile.length + ")", null);
					MainWindow.this.UpdateFrame();
				} catch (final IOException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
			}
			gif.finish();
			return "x";
		}

		/*
		 * Executed in event dispatching thread
		 */
		@Override
		public void done() {
			MainWindow.this.setCursor(null); // turn off the wait cursor
		}
	}

	private static final long serialVersionUID = 1111111100000000111L;

	private int currentFrame;

	private final EditToolBar editToolBar;

	private final JLabel imageLabel;
	private File[] partFile;
	private final Timer timer;
	private final StatusBar statusBar;
	private final FileToolBar fileToolBar;

	private final SettingsToolBar settingsToolBar;

	private final DecimalFormat decimalFormat;
	private long now;
	private final OpenAndSaveDialog fileChooser;

	private final ExportGifDialog exportGifDialog;
	private final Header header;

	public MainWindow() {

		// initialize
		this.fileToolBar = new FileToolBar(this);
		this.settingsToolBar = new SettingsToolBar(this);
		this.editToolBar = new EditToolBar(this);
		this.statusBar = new StatusBar();
		this.fileChooser = new OpenAndSaveDialog();
		this.exportGifDialog = new ExportGifDialog();
		this.timer = new Timer(100, this);
		this.timer.setActionCommand("timer");
		this.decimalFormat = new DecimalFormat("000.0");
		this.header = new Header(Utils.getLabel("title"), "",
				Utils.getIcon("video.png"));
		this.currentFrame = 0;

		// create GUI
		this.setLayout(new BorderLayout());
		this.setBackground(new Color(0x86, 0xab, 0xd9));

		final ToolBar ToolBarTop = new ToolBar("", null,
				SwingConstants.HORIZONTAL);
		ToolBarTop.setLayout(new BorderLayout());
		ToolBarTop.setFloatable(false);
		ToolBarTop.add(this.fileToolBar, BorderLayout.WEST);
		ToolBarTop.add(this.settingsToolBar, BorderLayout.EAST);

		final JPanel ToolBarLeft = new JPanel();
		ToolBarLeft.setLayout(new BorderLayout());
		ToolBarLeft.setBackground(new Color(0x86, 0xab, 0xd9));
		ToolBarLeft.add(this.editToolBar, BorderLayout.NORTH);

		final ImageIcon startImage = Utils.getIcon("droid_0.png");
		this.imageLabel = new JLabel(startImage);

		final JPanel pCenter = new JPanel();
		pCenter.setLayout(new BoxLayout(pCenter, BoxLayout.PAGE_AXIS));

		final JScrollPane spCenter = new JScrollPane(this.imageLabel);
		spCenter.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
		this.header.setColorStart(new Color(0x86, 0xab, 0xd9));
		// header.setColorStart(new Color(0xcf, 0xde, 0xf0));
		pCenter.add(this.header);
		pCenter.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
		pCenter.add(spCenter);
		this.add(ToolBarTop, BorderLayout.PAGE_START);
		this.add(pCenter, BorderLayout.CENTER);
		this.add(ToolBarLeft, BorderLayout.LINE_END);
		this.add(this.statusBar, BorderLayout.PAGE_END);

		// New
		this.actionPerformed(new ActionEvent(this, 0, "new"));
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		Utils.logger.log(Level.INFO, e.getActionCommand());
		if (e.getActionCommand().equals("new")) {

			// Crea un nuovo bootanimation.zip
			// pulizia della cartella Work
			Utils.cleanDirectory(new File(Utils.WorkPath));
			// lettura del file desc.txt
			this.editToolBar.loadDesc(BootAnimationZip
					.getDescription(Utils.WorkDescPath));
			// recupero dei frame
			this.partFile = this.editToolBar.getPartFile();

			this.currentFrame = 0;

			this.header.setTitle(Utils.getLabel("header.new.title"));
			this.header
					.setDescription(Utils.getLabel("header.new.description"));
			this.header.repaint();

		} else if (e.getActionCommand().equals("save")) {

			// Salva un bootanimation.zip
			// finestra di selezione del file
			final int result = this.fileChooser.showSaveDialog(this);
			if (result == JFileChooser.APPROVE_OPTION) {
				final File fileToSave = this.fileChooser.getSelectedFile();
				System.out.println("Save as file: "
						+ fileToSave.getAbsolutePath());
				// compressione della cartella Work nello zip
				BootAnimationZip.save(Utils.WorkPath, this.fileChooser
						.getSelectedFile().getAbsolutePath());

			}
			// TODO da completare!

		} else if (e.getActionCommand().equals("open")) {

			// Apri un bootanimation.zip esistente
			// finestra di selezione del file
			final int result = this.fileChooser.showOpenDialog(this);
			if (result == JFileChooser.APPROVE_OPTION) {
				// pulizia della cartella Work
				Utils.cleanDirectory(new File(Utils.WorkPath));
				// estrazione dello zip nella cartella Work
				BootAnimationZip.open(this.fileChooser.getSelectedFile()
						.getAbsolutePath(), Utils.WorkPath);
				// lettura del file desc.txt
				this.editToolBar.loadDesc(BootAnimationZip
						.getDescription(Utils.WorkDescPath));
				// recupero dei frame
				this.partFile = this.editToolBar.getPartFile();

				this.header.setTitle(this.fileChooser.getSelectedFile()
						.getName());
				this.header.repaint();
			}

		} else if (e.getActionCommand().equals("export")) {

			// Estrae un bootanimation.zip dal dispositivo

			JOptionPane.showMessageDialog(null, CommonAdb.getDevice(),
					"Dispositivo", JOptionPane.INFORMATION_MESSAGE);

			// copia il bootanimation.zip
			CommonAdb.pull(Utils.RemoteZipPath, Utils.WorkZipPath);
			// pulizia della cartella Work
			Utils.cleanDirectory(new File(Utils.WorkPath));
			// estrazione dello zip nella cartella Work
			BootAnimationZip.open(Utils.WorkZipPath, Utils.WorkPath);
			// pulizia dello zip nella cartella Work
			BootAnimationZip.delete(Utils.WorkZipPath);
			// lettura del file desc.txt
			this.editToolBar.loadDesc(BootAnimationZip
					.getDescription(Utils.WorkDescPath));
			// recupero dei frame
			this.partFile = this.editToolBar.getPartFile();

		} else if (e.getActionCommand().equals("install")) {

			// Installare un bootanimation.zip nel dispositivo

			JOptionPane.showMessageDialog(null, CommonAdb.getDevice(),
					"Dispositivo", JOptionPane.INFORMATION_MESSAGE);

			// pulizia dello zip nella cartella Work
			BootAnimationZip.delete(Utils.WorkZipPath);

			// compressione della cartella Work nello zip
			BootAnimationZip.save(Utils.WorkPath, Utils.WorkZipPath);

			// copia il bootanimation.zip
			CommonAdb.push(Utils.WorkZipPath, "/data/local"); // Utils.RemoteZipPath);

		} else if (e.getActionCommand().equals("gif")) {

			// Esporta in GIF
			final int result = this.exportGifDialog.showSaveDialog(this);
			if (result == JFileChooser.APPROVE_OPTION) {
				final File fileToSave = this.exportGifDialog.getSelectedFile();
				final MakeGifTask task = new MakeGifTask(
						fileToSave.getAbsolutePath());
				task.execute();
			}

		} else if (e.getActionCommand().equals("part.change")) {

			this.partFile = this.editToolBar.getPartFile();
			this.currentFrame = 0;
			this.UpdateFrame();

		} else if (e.getActionCommand().equals("frame.prev")) {

			// vai al frame precedente
			if (this.currentFrame > 0) {
				this.currentFrame--;
				this.UpdateFrame();
			}

		} else if (e.getActionCommand().equals("frame.next")) {

			// vai al frame successivo
			if (this.currentFrame < this.partFile.length) {
				this.currentFrame++;
				this.UpdateFrame();
			}

		} else if (e.getActionCommand().equals("fps")) {

			// imposta il Delay
			this.timer.setDelay(e.getID());

		} else if (e.getActionCommand().equals("timer")) {
			this.step();
		} else if (e.getActionCommand().equals("video.start")) {

			// avvia anteprima
			this.statusBar.setMessage("Play", Utils.getIcon("play.png"));
			this.currentFrame++;
			this.now = System.currentTimeMillis();
			this.currentFrame = 0;
			this.timer.start();

		} else if (e.getActionCommand().equals("video.stop")) {

			// ferma anteprima
			this.statusBar.setMessage("Stop", Utils.getIcon("pause.png"));
			this.timer.stop();
			this.currentFrame = 0;
			this.UpdateFrame();

		} else if (e.getActionCommand().equals("settings")) {

			// apri la finestra delle impostazioni
			final SettingsDialog sd = new SettingsDialog();
			sd.setLocationRelativeTo(null);
			sd.setVisible(true);

		} else if (e.getActionCommand().equals("about")) {

			// apri la finestra delle informazioni
			final AboutDialog ad = new AboutDialog();
			ad.setLocationRelativeTo(null);
			ad.setVisible(true);

		} else if (e.getActionCommand().equals("part.add")) {

			// aggiungi porzione
			this.editToolBar.addPart();

		} else if (e.getActionCommand().equals("part.remove")) {

			// rimuovi porzione
			if (this.editToolBar.getPart() != null) {
				this.editToolBar.removePart();
			} else {
				JOptionPane.showMessageDialog(null,
						Utils.getLabel("toolbar.part.remove.error"),
						Utils.getLabel("toolbar.part.remove"),
						JOptionPane.INFORMATION_MESSAGE);
			}

		} else if (e.getActionCommand().equals("frame.edit")) {

			// edita frame
			if (this.editToolBar.getPart() != null) {
				this.editToolBar.editFrame(this.partFile[this.currentFrame]);
			}

		} else if (e.getActionCommand().equals("frame.add")) {

			// aggiungi frame
			if (this.editToolBar.getPart() != null) {
				final DecimalFormat df = new DecimalFormat("0000");
				final String fileName = "f" + df.format(this.currentFrame + 1)
						+ "added.png";
				this.editToolBar.addFrame(fileName);

				this.partFile = this.editToolBar.getPartFile();
				if (this.currentFrame > 0) {
					this.currentFrame++;
				}
				this.UpdateFrame();
			} else {
				JOptionPane.showMessageDialog(null,
						Utils.getLabel("toolbar.frame.add.error.a"),
						Utils.getLabel("toolbar.frame.add"),
						JOptionPane.INFORMATION_MESSAGE);
			}
		} else if (e.getActionCommand().equals("frame.remove")) {

			// rimuovi frame
			if ((this.editToolBar.getPart() != null)
					&& (this.partFile.length > 0)) {
				this.editToolBar.removeFrame(this.partFile[this.currentFrame]);
			} else {
				JOptionPane.showMessageDialog(null,
						Utils.getLabel("toolbar.frame.remove.error"),
						Utils.getLabel("toolbar.frame.remove"),
						JOptionPane.INFORMATION_MESSAGE);
			}
		}
	}

	private void step() {
		this.currentFrame++;
		if (this.currentFrame >= this.partFile.length) {
			this.now = System.currentTimeMillis();
			this.currentFrame = 0;
		}
		this.statusBar
				.setMessage("Play "
						+ this.decimalFormat.format((System.currentTimeMillis() - this.now) / 1000d));
		this.UpdateFrame();
	}

	private void UpdateFrame() {

		BufferedImage bufferedImageIO;
		try {
			bufferedImageIO = ImageIO.read(this.partFile[this.currentFrame]);
			final ImageIcon imageIcon = new ImageIcon(bufferedImageIO);
			this.imageLabel.setIcon(imageIcon);
			this.header.setDescription(Utils.FileSeparator
					+ this.editToolBar.getPart() + Utils.FileSeparator
					+ this.partFile[this.currentFrame].getName());
			this.repaint();
		} catch (final IOException e) {

			e.printStackTrace();
		}
	}

}